package com.l2jserver.gameserver.myclient;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.logging.Logger;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;

import javolution.util.FastMap;

public class MyServer extends Thread 
{
	private static final Logger _log = Logger.getLogger(MyServer.class.getName());
	
	private ServerSocket Server;
	boolean _canlogin = false;
	String _address = "";
	String _account = null;
	public FastMap<String, Socket> _allclient = new FastMap<String, Socket>();
	static MyServer my;
	
	public static final MyServer getInstance()
	{
		return SingletonHolder._instance;
	}
	
	public MyServer()
	{
		try {
			Server = new ServerSocket(4000);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		_log.info("# ANTI-BOT-SYSTEM: Il Server e' in attesa sulla porta " + Server.getLocalPort());
		this.start();
	}
	
	public void run()
	{
		for(;;)
		{
			if(_canlogin){
			try {
					//_log.info("In attesa di Connessione.");
					Server.setSoTimeout(1000);
					Socket client;
					try{
						client = Server.accept();
					}
					catch(SocketTimeoutException iioe){continue;}
					BufferedReader in = getIn(client);
					PrintStream out = new PrintStream(client.getOutputStream(), true);
					if(client.getInetAddress().getHostAddress().equalsIgnoreCase(_address))
					{
						if(!in.readLine().equalsIgnoreCase("67g54fue65!7684"))
						{
							out.close();
							in.close();
							client.close();
							disconnect(_account);
							//_log.info("MyClient: Psw Incorretta "+client.getInetAddress().getHostAddress()+","+_account);
							continue;
						}
						//_log.info("# ANTI-BOT-SYSTEM: MyClient - Connessione accettata da: " + client.getInetAddress().getHostAddress() + "," + _account);
						if(_allclient.containsKey(_account))
							_allclient.remove(_account);
						_allclient.put(_account, client);
					}
					else
					{
						in.close();
						out.close();
						client.close();
						disconnect(_account);
					}
				}
			catch(IOException e) {}}
			}
	}
	
	public boolean checkClient(String acc) 
	{
		Socket c =_allclient.get(acc);
		if (c == null)
			return false;
		try 
		{
			c.setSoTimeout(1000);
		} 
		catch (SocketException e) {	_log.info("# ANTI-BOT-SYSTEM: Problema sul setSoTimeout");
		disconnect(acc); return false;}
		PrintStream out = getOut(c);
		BufferedReader in = getIn(c);
		if (in == null)
			return false;
		out.println("0x00");
		out.flush();
		String mex = "";
		try
		{
			try
			{
				mex = in.readLine();
				if(mex.equalsIgnoreCase("1x00"))
					return true;
			}
			catch (InterruptedIOException iioe)
			{
				_log.info("# ANTI-BOT-SYSTEM: Check Timeout occurred - killing connection");
				c.close();
				disconnect(acc);
				return false;
			}
		}
		catch (IOException ioe)
		{disconnect(acc); return false;}	
		try {c.close(); disconnect(acc); return false;} catch (IOException e) {return false;}
		//return false;
	}
	
	public boolean isMultiBox(String acc)  
	{
		Collection<L2PcInstance> allPlayers = L2World.getInstance().getAllPlayers().values();
		L2PcInstance[] players = allPlayers.toArray(new L2PcInstance[allPlayers.size()]);
		//Socket c;
		String host = getHostName(acc);
		String host1;
		for (L2PcInstance player : players)
		{
			host1 = getHostName(player.getAccountName());
			if (host1 == null)
			{
				{try {_allclient.get(player.getAccountName()).close();} catch (IOException e) {}}
				_allclient.remove(player.getAccountName());
				player.logout();
				continue;
			}
			if(host.equalsIgnoreCase(host1))
			{
				/*_allclient.get(player.getAccountName()).close();
				disconnect(acc);*/
				return true;
			}
		}
		return false;
	}
	
	public String getHostName(String acc) 
	{
		Socket c =_allclient.get(acc);
		try 
		{
			c.setSoTimeout(1000 );
		} 
		catch (SocketException e) {	_log.info("# ANTI-BOT-SYSTEM: Problema sul setSoTimeout"); 
		disconnect(acc);return null;}
		PrintStream out = getOut(c);
		BufferedReader in = getIn(c);
		out.println("hostname");
		out.flush();
		try
		{
			try
			{
				return in.readLine();
			}
			catch (InterruptedIOException iioe)
			{
				_log.info("# ANTI-BOT-SYSTEM: Host Timeout occurred - killing connection");
				disconnect(acc);
				c.close();
				return null;
			}
		}
		catch (IOException ioe)
		{disconnect(acc);return null;}
	}
	
	public boolean isBotter(String acc) 
	{
		Socket c =_allclient.get(acc);
		try 
		{
			c.setSoTimeout(1000);
		} 
		catch (SocketException e) {	_log.info("# ANTI-BOT-SYSTEM: Problema sul setSoTimeout"); 
		disconnect(acc);return true;}
		PrintStream out = getOut(c);
		BufferedReader in = getIn(c);
		out.println("0x01");
		out.flush();
		String mex = "";
		try
		{
			try
			{
				mex = in.readLine();
				if(mex.equalsIgnoreCase("1x11"))
				{
					c.close();
					disconnect(acc);
					return true;
				}
				else if(mex.equalsIgnoreCase("1x01"))
					return false;
			}
			catch (InterruptedIOException iioe)
			{
				//_log.info("Bot Timeout occurred - killing connection");
				c.close();
				disconnect(acc);
				return false;
			}
		}
		catch (IOException ioe)
		{disconnect(acc);return true;}
		return true;
	}
	
	public BufferedReader getIn(Socket c)
	{
		try{
			return new BufferedReader(new InputStreamReader(c.getInputStream()));}
		catch(Exception e1)
		{
			try { c.close();}
			catch(Exception e) 
			{
				_log.info("# ANTI-BOT-SYSTEM: " + e.getMessage());
			}
			return null;
		}
	}
	
	public PrintStream getOut(Socket c)
	{
		try {
			return new PrintStream(c.getOutputStream(), true);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}
	
	public synchronized void setCanLogin(String ip, String acco)
	{
		_address = ip;
		_account = acco;
		_canlogin = true;
	}
	
	public synchronized void unLogin()
	{
		_canlogin = false;
		_account = null;
		_address = null;
	}

	public void disconnect(String acc)
	{
		try {
			_allclient.get(acc).close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		_allclient.remove(acc);
		/*L2PcInstance p = getPlayer(acc);
		if(p != null)
		{
			if(ingame)
				p.logout();
			else
				p.getClient().closeNow();
		}*/
	}
	
	public L2PcInstance getPlayer(String acc)
	{
		Collection<L2PcInstance> allPlayers = L2World.getInstance().getAllPlayers().values();
		L2PcInstance[] players = allPlayers.toArray(new L2PcInstance[allPlayers.size()]);
		for (L2PcInstance pla : players)
		{
			if(pla.getAccountName().equalsIgnoreCase(acc))
			{
				return pla;
			}
		}
		return null;
	}
	
	
	public Socket getMyClient(String acc)
	{
		return _allclient.get(acc);
	}
	
	public Socket removeMyClient(String acco)
	{
		return _allclient.remove(acco);
	}
	
	@SuppressWarnings("synthetic-access")
	private static class SingletonHolder
	{
		protected static final MyServer _instance = new MyServer();
	}
}